package com.jungle.client;

import com.google.gson.reflect.TypeToken;
import com.jungle.client.vo.DataDefinitionVo;
import com.jungle.client.channel.HttpClient;
import com.jungle.client.vo.ApiMetadataVo;
import com.jungle.client.vo.BizTreeVo;
import com.jungle.client.vo.TreeItemInfo;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventTarget;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.function.Consumer;

import static com.jungle.client.control.DraggableTableCell.SERIALIZED_MIME_TYPE;

@Slf4j
public class DesktopController implements Initializable {
    @FXML
    private TreeView<TreeItemInfo> sysTree;
    @FXML
    private TreeTableView<ApiMetadataVo> treeTableView;
    /**
     * fxml文件中，定义引入组件id，才能注入组件的controller
     */
    @FXML
    private DataDefinitionController dataDefinitionController;

    public void initialize(URL location, ResourceBundle resources) {
        log.info("init DesktopController, location:{}", location);
        // 初始化数据并加载到界面
        refreshTree();

        initTreeTableView();
    }

    private void initTreeTableView() {
        // 拖拽事件源
        treeTableView.setRowFactory(tv -> {
            TreeTableRow<ApiMetadataVo> row = new TreeTableRow<>();
            row.setOnDragDetected(event -> {
                if (!row.isEmpty()) {
                    Dragboard dragboard = row.startDragAndDrop(TransferMode.MOVE);
                    dragboard.setDragView(row.snapshot(null, null));
                    ClipboardContent content = new ClipboardContent();
                    ApiMetadataVo metadataVo = row.getTreeItem().getValue();
                    content.put(SERIALIZED_MIME_TYPE, metadataVo);
                    dragboard.setContent(content);
                    event.consume();
                }
            });
            return row;
        });
    }

    @FXML
    protected void onContextMenuRequested(Event event) {
        EventTarget target = event.getTarget();
        if (target instanceof AnchorPane anchorPane) {
            log.info("targetID:{}", anchorPane.getId());
        } else {
            log.info("target:{}", target);
        }
        log.info("context menu requested");
    }

    /**
     * 加入新的api
     *
     * @param actionEvent 触发事件
     */
    public void onActionNew(ActionEvent actionEvent) throws IOException {
        log.info("onActionNew {}", actionEvent);
        PopupController.showAddDialog("", apiUrl -> {
            log.info("popup: {}", apiUrl);

            Map<String, Object> params = new HashMap<>();
            params.put("apiUrl", apiUrl);
            HttpClient.getInstance().get("/bizSystem/analyse", params).callback(new TypeToken<List<BizTreeVo>>() {
            }, resp -> {
                log.info("resp: {}", resp);
                refreshTree();
            });
        });
    }

    /**
     * 删除指定 api
     *
     * @param actionEvent 触发事件
     */
    public void onActionDel(ActionEvent actionEvent) {
        log.info("onActionDel {}", actionEvent);
        MultipleSelectionModel<TreeItem<TreeItemInfo>> selectionModel = sysTree.getSelectionModel();
        TreeItem<TreeItemInfo> selectedItem = selectionModel.getSelectedItem();
        TreeItemInfo value = selectedItem.getValue();
        log.info("delete api");

        HttpClient.getInstance().post("/bizSystem/delete", value).callback(Void.class, resp -> {
            log.info("resp: {}", resp);
            refreshTree();
        });
    }

    /**
     * 刷新数据
     *
     * @param actionEvent 触发事件
     */
    public void onActionRefresh(ActionEvent actionEvent) {
        log.info("onActionRefresh {}", actionEvent);
        // 刷新数据
        // 创建根节点
        refreshTree();
    }

    private void refreshTree() {
        log.debug("refresh biz system tree");
        TreeItem<TreeItemInfo> rootNode = new TreeItem<>(new TreeItemInfo("系统&模块"));
        HttpClient.getInstance().get("/bizSystem/findAll").callback(new TypeToken<>() {
        }, list2tree(rootNode));

        rootNode.setExpanded(true);

        sysTree.setRoot(rootNode);

        sysTree.setShowRoot(true);
    }

    private static Consumer<List<BizTreeVo>> list2tree(TreeItem<TreeItemInfo> rootNode) {
        return list -> {
            if (list == null || list.isEmpty()) {
                return;
            }
            // 获取所有id
            List<String> ids = list.stream().map(BizTreeVo::getId).toList();
            List<BizTreeVo> childrenList = list.stream().filter(vo -> ids.contains(vo.getParentId())).toList();
            // 获取所有一级节点(没有父级节点)
            list.stream().filter(vo -> !ids.contains(vo.getParentId())).forEach(vo -> {
                TreeItem<TreeItemInfo> node = new TreeItem<>(new TreeItemInfo(vo.getId(), vo.getApiId(), vo.getPath(), vo.getTitle(), vo.getType(), vo.getSchemaType(), vo.getSchemaType(), vo.getMethod()));
                addChildNode(node, childrenList);
                // 添加子节点
                rootNode.getChildren().add(node);
            });
        };
    }

    private static void addChildNode(TreeItem<TreeItemInfo> rootNode, List<BizTreeVo> list) {
        String parentId = rootNode.getValue().getId();
        list.stream().filter(vo -> vo.getParentId().equals(parentId)).forEach(vo -> {
            TreeItem<TreeItemInfo> node = new TreeItem<>(new TreeItemInfo(vo.getId(), vo.getApiId(), vo.getPath(), vo.getTitle(), vo.getType(), vo.getSchemaType(), vo.getSchemaRef(), vo.getMethod()));
            addChildNode(node, list);
            // 添加子节点
            rootNode.getChildren().add(node);
        });
    }

    public void onMouseClicked(MouseEvent mouseEvent) {
        if (mouseEvent.getClickCount() == 1) {
            TreeItem<TreeItemInfo> selectedItem = sysTree.getSelectionModel().getSelectedItem();
            if (selectedItem == null) {
                log.info("no selected item");
                return;
            }
            TreeItemInfo value = selectedItem.getValue();
            log.info("click: {}", value);
            loadTreeTable(value);
        }
    }

    private void loadTreeTable(TreeItemInfo value) {
        if ("SYSTEM".equals(value.getType()) || "MODULE".equals(value.getType())) {
            //非叶子节点
            log.info("非叶子节点:{}", value.getId());
        } else if ("FUNCTION".equals(value.getType())) {
            //叶子节点
            HttpClient.getInstance().post("/metadata/findAll", value).callback(new TypeToken<List<ApiMetadataVo>>() {
            }, this::loadTreeTable);

            DataDefinitionVo dataDefinitionVo = new DataDefinitionVo();
            dataDefinitionVo.setApiId(value.getApiId());
            dataDefinitionVo.setApiPath(value.getPath());
            // 加载DataDefinition数据
            dataDefinitionController.loadData(dataDefinitionVo);
        }
    }

    private void loadTreeTable(List<ApiMetadataVo> list) {
        getTop(list).ifPresent(top -> {
            TreeItem<ApiMetadataVo> rootNode = new TreeItem<>(top);
            this.addChildNode(list, rootNode, rootNode);
            rootNode.setExpanded(true);

            treeTableView.setRoot(rootNode);
        });
    }

    private void addChildNode(List<ApiMetadataVo> list, TreeItem<ApiMetadataVo> parentNode, TreeItem<ApiMetadataVo> attachedParentNode) {
        list.stream().filter(metadataVo -> metadataVo.getParentPath().equals(parentNode.getValue().getOwnPath())).forEach(metadataVo -> {
            TreeItem<ApiMetadataVo> thisNode = new TreeItem<>(metadataVo);
            if ("array".equals(metadataVo.getOriginType())) {
                log.info("array:{}", metadataVo);
                //获取数组数据类型
                list.stream().filter(metadataVo1 -> metadataVo1.getParentPath().equals(thisNode.getValue().getOwnPath())).findFirst()
                        .ifPresent(metadataVo1 -> thisNode.getValue().setRef(metadataVo1.getRef()));
                collapsedNode(thisNode);
            } else if ("ref".equals(metadataVo.getOriginType())) {
                log.info("ref:{}", metadataVo);
                collapsedNode(thisNode);
            } else {
                addChildNode(list, thisNode, attachedParentNode);
                attachedParentNode.setExpanded(true);
            }
            attachedParentNode.getChildren().add(thisNode);
        });
    }

    private void collapsedNode(TreeItem<ApiMetadataVo> node) {
        node.setExpanded(false);
        node.getChildren().add(new TreeItem<>());
        node.expandedProperty().addListener((observable, oldValue, newValue) -> {
            if (Boolean.TRUE.equals(newValue) && node.getChildren().get(0).getValue() == null) {
                node.getChildren().clear();
                ApiMetadataVo value = node.getValue();
                if (value.getRef() == null) {
                    log.info("对象({})的数据类型为空", value.getName());
                    return;
                }
                TreeItemInfo info = new TreeItemInfo(value.getApiId(), value.getName(), value.getRef());
                log.info("展开节点：{}", info);
                HttpClient.getInstance().post("/metadata/findAll", info).callback(new TypeToken<>() {
                }, loadObjectNode(node));
            }
        });
    }

    private Consumer<List<ApiMetadataVo>> loadObjectNode(TreeItem<ApiMetadataVo> attachedParentNode) {
        return list -> getTop(list).ifPresent(top -> {
            TreeItem<ApiMetadataVo> parentNode = new TreeItem<>(top);
            this.addChildNode(list, parentNode, attachedParentNode);
            parentNode.setExpanded(true);
        });
    }

    private Optional<ApiMetadataVo> getTop(List<ApiMetadataVo> list) {
        return list.stream().filter(vo -> vo.getParentPath().equals("$")).findFirst();
    }

    public void onMouseClicked4treeTableView(MouseEvent mouseEvent) {
        if (mouseEvent.getClickCount() == 1) {
            TreeItem<ApiMetadataVo> selectedItem = treeTableView.getSelectionModel().getSelectedItem();
            if (selectedItem == null) {
                log.info("no selected item");
                return;
            }
            ApiMetadataVo value = selectedItem.getValue();
            log.info("点击: {}", value);
            if ("$".equals(value.getParentPath())) {
                log.info("接口响应数据:{}", value);
                //获取数组数据类型

                //获取指定接口的 DataItem数据集合
                //httpClient.post("/DataItem/findAll", value).callback(DataItemVoList.class,;)
            }
        }
    }
}
